/**
 * 
 */
package org.xserver.runtime.jetty.command;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Properties;

import org.apache.log4j.Logger;
import org.eclipse.jetty.server.Server;
import org.xserver.annotation.PerformanceLog;
import org.xserver.annotation.VisitorLog;

/**
 * @author jkonopka
 * 
 */
public class ServerStartCommand extends AbstractServerCommand {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1893515478415840051L;

	/**
	 * 
	 */
	private static final String SERVER_VERSION = "server.version";

	/**
	 * 
	 */
	private static final String SERVER_STAGE = "server.stage";

	private final Server server;

	/**
	 * @param server {@link Server}
	 * @param properties {@link Properties}
	 */
	public ServerStartCommand(final Server server, final Properties properties) {
		super(properties);
		this.server = server;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.jserver.command.ICommand#execute()
	 */
	@Override
	@VisitorLog
	@PerformanceLog
	public void execute() throws Exception {
		final Thread monitor = new MonitorThread(server, getProperties());
		monitor.start();

		getLog().info(String.format("Server-Stage: %s", getProperties().getProperty(SERVER_STAGE)));
		getLog().info(String.format("Server-Version: %s", getProperties().getProperty(SERVER_VERSION)));
		getLog().info("Server wurde erfolgreich gestartet");

		server.start();
		server.join();

	}

	/**
	 * @author jkonopka
	 * 
	 */
	private static class MonitorThread extends Thread {

		/**
		 * 
		 */
		private static final String SERVER_STOP_PORT = "server.stop.port";

		/**
		 * 
		 */
		private static final String SERVER_ADDRESS = "server.address";

		private static final Logger LOG = Logger.getLogger(MonitorThread.class);

		private ServerSocket socket;
		private final Server server;
		private final Properties properties;

		/**
		 * @param server {@link Server}
		 * @param properties {@link Properties}
		 */
		public MonitorThread(final Server server, final Properties properties) {
			this.server = server;
			this.properties = properties;

			setDaemon(true);
			setName("StopMonitor");

			try {
				socket = new ServerSocket(getPort(), 1, getAddress());
			} catch (Exception e) {
				throw new RuntimeException(e);
			}
		}

		/**
		 * @return
		 * @throws UnknownHostException
		 */
		private InetAddress getAddress() throws UnknownHostException {
			return InetAddress.getByName(properties.getProperty(SERVER_ADDRESS));
		}

		/**
		 * @return
		 * @throws NumberFormatException
		 */
		private Integer getPort() throws NumberFormatException {
			return Integer.valueOf(properties.getProperty(SERVER_STOP_PORT));
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see java.lang.Thread#run()
		 */
		@Override
		public void run() {
			LOG.info("*** running jetty 'stop' thread ***");
			Socket accept;
			try {
				accept = socket.accept();
				BufferedReader reader = new BufferedReader(new InputStreamReader(accept.getInputStream()));
				reader.readLine();
				LOG.info("*** stopping jetty embedded server ***");
				server.stop();
				accept.close();
				socket.close();
			} catch (Exception e) {
				throw new RuntimeException(e);
			}
		}
	}

}
